"""
主题: 子类中扩展property
问题: 在子类中，你想要扩展定义在父类中的property的功能。
提示 : 
"""

class Person:
    def __init__(self, name):
        self.name = name

    # Getter function
    @property
    def name(self):
        return self._name

    # Setter function
    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._name = value

    # Deleter function
    @name.deleter
    def name(self):
        raise AttributeError("Can't delete attribute")


class SubPerson(Person):
    @property
    def name(self):
        print('Getting name')
        return super().name

    @name.setter
    def name(self, value):
        print('Setting name to', value)
        super(SubPerson, SubPerson).name.__set__(self, value)

    @name.deleter
    def name(self):
        print('Deleting name')
        super(SubPerson, SubPerson).name.__delete__(self)


# A descriptor
class String:
    '''描述器类'''
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, cls):
        if instance is None:
            return self
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        instance.__dict__[self.name] = value

    def __delete__(self, __name: str) -> None:
        raise AttributeError("Can't delete attribute")

# A class with a descriptor
class Person1:
    name = String('name')

    def __init__(self, name):
        self.name = name

# Extending a descriptor with a property
class SubPerson1(Person1):
    @property
    def name(self):
        print('Getting name')
        return super().name

    @name.setter
    def name(self, value):
        print('Setting name to', value)
        super(SubPerson1, SubPerson1).name.__set__(self, value)

    @name.deleter
    def name(self):
        print('Deleting name')
        super(SubPerson1, SubPerson1).name.__delete__(self)

def recipe1():
    s = SubPerson('Guido')
    print(f"{s.name = }")
    s.name = 'Larry'    
    print(f"{s.name = }")

    try:
        s.name = 42  # Calls the setter
    except TypeError as e:
        print(e)

    try:
        del s.name  # Calls the deleter
    except AttributeError as e:
        print(e) 

def recipe2():
    s = SubPerson1('Guido')
    print(f"{s.name = }")
    s.name = 'Larry'    
    print(f"{s.name = }")

    try:
        s.name = 42  # Calls the setter
    except TypeError as e:
        print(e)

    try:
        del s.name  # Calls the deleter
    except AttributeError as e:
        print(e)  

def main():
    print('recipe1'.center(20, '*'))
    recipe1()
    print('recipe2'.center(20, '*'))
    recipe2()

if __name__ == '__main__':
    main()    